package com.lemon.utils.pay;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SignatureException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.commons.codec.digest.DigestUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.lemon.model.buy.PayRefundResult;
import com.lemon.model.buy.PayTransfersResult;
import com.lemon.model.buy.PayUnifiedorderResult;
import com.lemon.utils.DateUtil;
import com.lemon.utils.MD5;
import com.lemon.utils.StringUtil;
  
public class PayUtil {  
	
	 private static final Logger log = LoggerFactory.getLogger(PayUtil.class);
     /**   
     * 签名字符串   
     * @param text需要签名的字符串   
     * @param key 密钥   
     * @param input_charset编码格式   
     * @return 签名结果   
     */     
    public static String sign(String text, String key, String input_charset) {     
        text = text + "&key=" + key;     
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));     
    }     
    /**   
     * 签名字符串   
     *  @param text需要签名的字符串   
     * @param sign 签名结果   
     * @param key密钥   
     * @param input_charset 编码格式   
     * @return 签名结果   
     */     
    public static boolean verify(String text, String sign, String key, String input_charset) {     
        text = text + key;     
        String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));     
        if (mysign.equals(sign)) {     
            return true;     
        } else {     
            return false;     
        }     
    }     
    /**   
     * @param content   
     * @param charset   
     * @return   
     * @throws SignatureException   
     * @throws UnsupportedEncodingException   
     */     
    public static byte[] getContentBytes(String content, String charset) {     
        if (charset == null || "".equals(charset)) {     
            return content.getBytes();     
        }     
        try {     
            return content.getBytes(charset);     
        } catch (UnsupportedEncodingException e) {     
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);     
        }     
    }     
      
    private static boolean isValidChar(char ch) {     
        if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))     
            return true;     
        if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))     
            return true;// 简体中文汉字编码     
        return false;     
    }     
    /**   
     * 除去数组中的空值和签名参数   
     * @param sArray 签名参数组   
     * @return 去掉空值与签名参数后的新签名参数组   
     */     
    public static Map<String, String> paraFilter(Map<String, String> sArray) {     
        Map<String, String> result = new HashMap<String, String>();     
        if (sArray == null || sArray.size() <= 0) {     
            return result;     
        }     
        for (String key : sArray.keySet()) {     
            String value = sArray.get(key);     
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")     
                    || key.equalsIgnoreCase("sign_type")) {     
                continue;     
            }     
            result.put(key, value);     
        }     
        return result;     
    }     
    /**   
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串   
     * @param params 需要排序并参与字符拼接的参数组   
     * @return 拼接后字符串   
     */     
    public static String createLinkString(Map<String, String> params) {     
        List<String> keys = new ArrayList<String>(params.keySet());     
        Collections.sort(keys);     
        String prestr = "";     
        for (int i = 0; i < keys.size(); i++) {     
            String key = keys.get(i);     
            String value = params.get(key);     
            if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符     
                prestr = prestr + key + "=" + value;     
            } else {     
                prestr = prestr + key + "=" + value + "&";     
            }     
        }     
        return prestr;     
    }   
    
    /**   
     *   
     * @param requestUrl请求地址    
     * @param requestMethod请求方法   
     * @param outputStr参数   
     */     
	public static String httpRequestApp(String requestUrl , String requestMethod , String outputStr) {
		// 创建SSLContext     
		StringBuffer buffer = null;
		try {
			URL url = new URL(requestUrl);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod(requestMethod);
			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.connect();
			//往服务器端写内容     
			if (null != outputStr) {
				OutputStream os = conn.getOutputStream();
				os.write(outputStr.getBytes("utf-8"));
				os.close();
			}
			// 读取服务器端返回的内容     
			InputStream is = conn.getInputStream();
			InputStreamReader isr = new InputStreamReader(is, "utf-8");
			BufferedReader br = new BufferedReader(isr);
			buffer = new StringBuffer();
			String line = null;
			while ((line = br.readLine()) != null) {
				buffer.append(line);
			}
			br.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return buffer.toString();
	}

	/**
	 * @param requestUrl请求地址
	 * @param requestMethod请求方法
	 * @param outputStr参数
	 */
    public static String httpRequest(String requestUrl,String requestMethod,String outputStr){     
        // 创建SSLContext     
        StringBuffer buffer = null;     
        try{     
            URL url = new URL(requestUrl);     
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();     
            conn.setRequestMethod(requestMethod);     
            conn.setDoOutput(true);     
            conn.setDoInput(true);     
            conn.connect();     
            //往服务器端写内容     
            if(null !=outputStr){     
                OutputStream os=conn.getOutputStream();     
                os.write(outputStr.getBytes("utf-8"));     
                os.close();     
            }     
            // 读取服务器端返回的内容     
            InputStream is = conn.getInputStream();     
            InputStreamReader isr = new InputStreamReader(is, "utf-8");     
            BufferedReader br = new BufferedReader(isr);     
            buffer = new StringBuffer();     
            String line = null;     
            while ((line = br.readLine()) != null) {     
                buffer.append(line);     
            }
            br.close();  
        }catch(Exception e){     
            e.printStackTrace();     
        }  
        return buffer.toString();  
    }       
    public static String urlEncodeUTF8(String source){     
        String result=source;     
        try {     
            result=java.net.URLEncoder.encode(source, "UTF-8");     
        } catch (UnsupportedEncodingException e) {     
            // TODO Auto-generated catch block     
            e.printStackTrace();     
        }     
        return result;     
    }   
    /** 
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点，则此节点的值是子节点的xml数据。 
     * @param strxml 
     * @return 
     * @throws JDOMException 
     * @throws IOException 
     */  
    public static Map<String,String> doXMLParse(String strxml) throws Exception {  
        if(null == strxml || "".equals(strxml)) {  
            return null;  
        }  
          
        Map<String,String> m = new HashMap<>();  
        InputStream in = String2Inputstream(strxml);  
        SAXBuilder builder = new SAXBuilder();  
        Document doc = builder.build(in);  
        Element root = doc.getRootElement();  
        List list = root.getChildren();  
        Iterator it = list.iterator();  
        while(it.hasNext()) {  
            Element e = (Element) it.next();  
            String k = e.getName();  
            String v = "";  
            List children = e.getChildren();  
            if(children.isEmpty()) {  
                v = e.getTextNormalize();  
            } else {  
                v = getChildrenText(children);  
            }  
              
            m.put(k, v);  
        }  
          
        //关闭流  
        in.close();  
          
        return m;  
    }  
    /** 
     * 获取子结点的xml 
     * @param children 
     * @return String 
     */  
    public static String getChildrenText(List children) {  
        StringBuffer sb = new StringBuffer();  
        if(!children.isEmpty()) {  
            Iterator it = children.iterator();  
            while(it.hasNext()) {  
                Element e = (Element) it.next();  
                String name = e.getName();  
                String value = e.getTextNormalize();  
                List list = e.getChildren();  
                sb.append("<" + name + ">");  
                if(!list.isEmpty()) {  
                    sb.append(getChildrenText(list));  
                }  
                sb.append(value);  
                sb.append("</" + name + ">");  
            }  
        }  
          
        return sb.toString();  
    }  
    public static InputStream String2Inputstream(String str) {  
        return new ByteArrayInputStream(str.getBytes());  
    }
    
  
    
    public static String getRandomStringByLength(int length) {  
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";  
        Random random = new Random();  
        StringBuffer sb = new StringBuffer();  
        for (int i = 0; i < length; i++) {  
            int number = random.nextInt(base.length());  
            sb.append(base.charAt(number));  
        }  
        return sb.toString();  
    }

	/**
	 * <b>Description:<blockquote> 支付
	 * </blockquote></b>
	 * 
	 * @Title: createrOrder
	 * @param appid
	 * @param openid
	 * @param body
	 * @param price
	 * @param orderNo
	 * @param ip
	 * @return
	 * @author Ran_cc
	 * @date 2018年11月30日
	 */
	public static PayUnifiedorderResult createrOrder(String appid , String openid , String body , int price ,
			String orderNo , String ip) {
		return createrOrder(appid , openid , body , price , orderNo , ip , "" , "");
	}



	/**
	 * <b>Description:<blockquote>
	 * </blockquote></b>
	 * 
	 * @Title: createrOrder
	 * @param appid          appid
	 * @param openid         openid
	 * @param body           商品名称
	 * @param price          商品价格 单位:分
	 * @param orderNo        本站唯一订单号
	 * @param ip             请求id
	 * @param pay_notify_url 回调地址
	 * @param attach         其他参数
	 * @return
	 * @author Ran_cc
	 * @date 2018年11月30日
	 */
	public static PayUnifiedorderResult createrOrder(String appid , String openid , String body , int price ,
			String orderNo , String ip , String pay_notify_url , String attach) {
    	PayUnifiedorderResult resp = new PayUnifiedorderResult();
    	try{
            //生成的随机字符串
            String nonce_str = PayUtil.getRandomStringByLength(32);
            //组装参数，用户生成统一下单接口的签名
            LocalDateTime  localTime = LocalDateTime.now();
            localTime = localTime.plusMinutes(5);//订单5分钟过期  
            String time_expire = DateUtil.formatLocalDateTimeToString(localTime,"yyyyMMddHHmmss");
            
            Map<String, String> packageParams = new HashMap<String, String>();
            packageParams.put("appid", appid);
            packageParams.put("mch_id", Constants.pay_mch_id);
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("body", body);
            packageParams.put("time_expire", time_expire);
			if (StringUtil.isNotBlank(attach)) {
				packageParams.put("attach" , attach);
			}
            packageParams.put("out_trade_no", orderNo);//商户订单号
			packageParams.put("total_fee" , price + "");//支付金额，这边需要转成字符串类型，否则后面的签名会失败
			packageParams.put("spbill_create_ip" , ip);
			log.info("pay_notify_url:" + pay_notify_url);
			if (StringUtil.isNotBlank(pay_notify_url)) {
				packageParams.put("notify_url" , pay_notify_url);//支付成功后的回调地址
			} else {
				packageParams.put("notify_url" , Constants.pay_notify_url);//支付成功后的回调地址
			}
            packageParams.put("trade_type", Constants.pay_TRADETYPE);//支付方式
            packageParams.put("openid", openid);
            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
            String mysign = PayUtil.sign(prestr, Constants.pay_key, "utf-8").toUpperCase();

            //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
            String xml = "<xml>" + "<appid>" + appid + "</appid>"
                    + "<body><![CDATA[" + body + "]]></body>"
                    + "<mch_id>" + Constants.pay_mch_id + "</mch_id>"
                    + "<nonce_str>" + nonce_str + "</nonce_str>"
					+ "<notify_url>"
					+ (StringUtil.isNotBlank(pay_notify_url) ? pay_notify_url : Constants.pay_notify_url)
					+ "</notify_url>"
                    + "<openid>" +openid + "</openid>"
                     + "<time_expire>" +time_expire + "</time_expire>"
                    + "<out_trade_no>" + orderNo + "</out_trade_no>"
                    + "<spbill_create_ip>" + ip + "</spbill_create_ip>"
                    + "<total_fee>" + price + "</total_fee>"
                    + "<trade_type>" + Constants.pay_TRADETYPE + "</trade_type>"
                    + "<sign>" + mysign + "</sign>"
					+ (StringUtil.isNotBlank(attach) ? "<attach>" + attach + "</attach>" : "")
                    + "</xml>";

            log.info("调试模式_统一下单接口 请求XML数据：" + xml);

            //调用统一下单接口，并接受返回的结果
            String result = PayUtil.httpRequest(Constants.pay_url, "POST", xml);

            log.info("调试模式_统一下单接口 返回XML数据：" + result);
  

            // 将解析结果存储在HashMap中
            Map<String,String> map = PayUtil.doXMLParse(result);
            
            String return_code =  map.get("return_code");//返回状态码
            if(isOk(return_code)){
            	resp.setSuccess(true);
                String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
                resp.setNoncestr(nonce_str);
                //response.put("package", "prepay_id=" + prepay_id);
                resp.setWxpackage("prepay_id=" + prepay_id);
                resp.setPrepayId(prepay_id);
                Long timeStamp = System.currentTimeMillis() / 1000;
                resp.setTimestamp(timeStamp+"");//这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误
                //拼接签名需要的参数
                String stringSignTemp = "appId=" + appid+ "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id+ "&signType=MD5&timeStamp=" + timeStamp;
                //再次签名，这个签名用于小程序端调用wx.requesetPayment方法
                String paySign = PayUtil.sign(stringSignTemp, Constants.pay_key, "utf-8").toUpperCase();
                resp.setAppId(appid);
                resp.setPaySign(paySign);
            } 
        }catch(Exception e){
            e.printStackTrace();
        }
        return resp;
    }

	/**
	 * 支付
	 * 
	 * @param openid  用户openid
	 * @param body    商品名称
	 * @param price   价格 分为单位
	 * @param orderNo 订单号
	 * @param ip      ip
	 * @return
	 */
	public static PayUnifiedorderResult createrOrderApp(String appid , String body , int price , String orderNo ,
			String ip , String attach) {
		PayUnifiedorderResult resp = new PayUnifiedorderResult();
		try {
			//生成的随机字符串
			String nonce_str = PayUtil.getRandomStringByLength(32);
			//组装参数，用户生成统一下单接口的签名
			LocalDateTime localTime = LocalDateTime.now();
			localTime = localTime.plusMinutes(5);//订单5分钟过期  
			String time_expire = DateUtil.formatLocalDateTimeToString(localTime , "yyyyMMddHHmmss");

			Map<String , String> packageParams = new HashMap<String , String>();
			packageParams.put("appid" , appid);
			packageParams.put("mch_id" , Constants.pay_mch_id_app);
			packageParams.put("nonce_str" , nonce_str);
			packageParams.put("body" , body);
			packageParams.put("time_expire" , time_expire);

			packageParams.put("attach" , attach);
			packageParams.put("out_trade_no" , orderNo);//商户订单号
			packageParams.put("total_fee" , price + "");//支付金额，这边需要转成字符串类型，否则后面的签名会失败
			packageParams.put("spbill_create_ip" , ip);
			packageParams.put("notify_url" , Constants.pay_notify_url_APP);//支付成功后的回调地址
			packageParams.put("trade_type" , Constants.pay_TRADETYPE_APP);//支付方式

			String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
			//MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
			String mysign = PayUtil.sign(prestr , Constants.pay_key , "utf-8").toUpperCase();
			//拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
			String xml = "<xml>" + "<appid>" + appid + "</appid>" + "<body><![CDATA[" + body + "]]></body>" + "<mch_id>"
					+ Constants.pay_mch_id_app + "</mch_id>" + "<nonce_str>" + nonce_str + "</nonce_str>"
					+ "<notify_url>"
					+ Constants.pay_notify_url_APP + "</notify_url>" + "<time_expire>"
					+ time_expire + "</time_expire>" + "<attach>" + attach + "</attach>" + "<out_trade_no>" + orderNo
					+ "</out_trade_no>"
					+ "<spbill_create_ip>" + ip + "</spbill_create_ip>" + "<total_fee>" + price + "</total_fee>"
					+ "<trade_type>" + Constants.pay_TRADETYPE_APP + "</trade_type>" + "<sign>" + mysign + "</sign>"
					+ "</xml>";

			log.info("调试模式_统一下单接口 请求XML数据：" + xml);

			//调用统一下单接口，并接受返回的结果
			String result = PayUtil.httpRequestApp(Constants.pay_url , "POST" , xml);

			log.info("调试模式_统一下单接口 返回XML数据：" + result);

			// 将解析结果存储在HashMap中
			Map<String , String> map = PayUtil.doXMLParse(result);

			String return_code = map.get("return_code");//返回状态码
			if (isOk(return_code)) {
				resp.setSuccess(true);
				String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
				resp.setNoncestr(nonce_str);
				//response.put("package", "prepay_id=" + prepay_id);
				resp.setWxpackage("prepay_id=" + prepay_id);
				resp.setPrepayId(prepay_id);
				Long timeStamp = System.currentTimeMillis() / 1000;
				resp.setTimestamp(timeStamp + "");//这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误
				//拼接签名需要的参数
				String stringSignTemp = "appid=" + appid + "&noncestr=" + nonce_str + "&package=Sign=WXPay&partnerid="
						+ Constants.pay_mch_id_app + "&prepayid=" + prepay_id + "&timestamp=" + timeStamp;
				//再次签名，这个签名用于小程序端调用wx.requesetPayment方法
				String paySign = MD5.getMD5(stringSignTemp + "&key=" + Constants.pay_key);
				//				String paySign = PayUtil.sign(stringSignTemp , Constants.pay_key , "utf-8").toUpperCase();
				resp.setAppId(appid);
				resp.setPaySign(paySign);
				resp.setPartnerId(Constants.pay_mch_id_app);

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return resp;
	}
    
	/**
	 * <b>Description:<blockquote>退款
	 * </blockquote></b>
	 * 
	 * @Title: refund
	 * @param appid
	 * @param orderNo       //本站订单号
	 * @param out_refund_no //本站订单退款单号
	 * @param total_fee     //标价金额
	 * @param refund_fee    //实际退款金额
	 * @param notify_url
	 * @return
	 * @author Ran_cc
	 * @date 2018年12月1日
	 */
    public static PayRefundResult refund(String appid,String orderNo,String out_refund_no,int total_fee,int refund_fee,String notify_url){
    	PayRefundResult result = new PayRefundResult();
    	try{
    		//生成的随机字符串
            String nonce_str = PayUtil.getRandomStringByLength(32);
            //组装参数，用户生成退款接口的签名
            Map<String, String> packageParams = new HashMap<String, String>();
            packageParams.put("appid", appid);
            packageParams.put("mch_id", Constants.pay_mch_id);
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("out_trade_no", orderNo);//商户订单号
            packageParams.put("out_refund_no", out_refund_no);//退款订单号
            
            packageParams.put("total_fee", String.valueOf(total_fee));//支付金额，这边需要转成字符串类型，否则后面的签名会失败
            packageParams.put("refund_fee", String.valueOf(refund_fee));
            if(StringUtil.isEmpty(notify_url)){
            	packageParams.put("notify_url", Constants.refund_notify_url);//退款成功后的回调地址
            }
            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
            String mysign = PayUtil.sign(prestr, Constants.pay_key, "utf-8").toUpperCase();
            String xml = "<xml>" + "<appid>" + appid + "</appid>"
                    + "<mch_id>" + Constants.pay_mch_id + "</mch_id>"
                    + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<notify_url>" + Constants.refund_notify_url + "</notify_url>"
                    + "<out_trade_no>" + orderNo + "</out_trade_no>"
                    + "<out_refund_no>" + out_refund_no + "</out_refund_no>"
                    + "<refund_fee>" + refund_fee + "</refund_fee>"
                    + "<total_fee>" + total_fee + "</total_fee>"
                    + "<transaction_id></transaction_id>"
                    + "<sign>" + mysign + "</sign>"
                    + "</xml>";
          //带证书的post
           log.info("调试模式_退款接口  请求XML数据：" + xml);
            String resXml = CertHttpUtil.postData("https://api.mch.weixin.qq.com/secapi/pay/refund", xml);
            log.info("调试模式_退款接口 返回XML数据：" + resXml);
            // 将解析结果存储在HashMap中
            Map<String,String> map = PayUtil.doXMLParse(resXml);
            
            String return_code =  map.get("return_code");//返回状态码
            result.setXmlString(resXml);
            if(isOk(return_code)){
            	if(isOk(map.get("result_code"))) result.setSuccess(true);
            	result.setOutRefundNo(map.get("out_refund_no"));
            	result.setTransactionId(map.get("transaction_id"));
            	result.setTotalFee(Integer.parseInt(map.get("total_fee")));
            	result.setOutTradeNo(map.get("out_trade_no"));
            	result.setRefundFee(Integer.parseInt(map.get("refund_fee")));
            }
            return result;
    	}catch(Exception e){
    	}
    	return result;
    }
    
    /**
     * 提现(企业付款)
     * @param openid
     * @param desc
     * @param amount
     * @param orderNo
     * @param ip
     * @return
     */
    public static PayTransfersResult transfers(String openid, String desc,int amount,String orderNo,String ip){
    	PayTransfersResult resp = new PayTransfersResult();
    	try{
            //生成的随机字符串
            String nonce_str = PayUtil.getRandomStringByLength(32);
            //组装参数，用户生成统一下单接口的签名
            Map<String, String> packageParams = new HashMap<String, String>();
            packageParams.put("mch_appid", Constants.pay_appid);
            packageParams.put("mchid", Constants.pay_mch_id);
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("desc", desc);
            packageParams.put("partner_trade_no", orderNo);//商户订单号
            packageParams.put("amount", String.valueOf(amount));//支付金额，这边需要转成字符串类型，否则后面的签名会失败
            packageParams.put("check_name", "NO_CHECK");
          //  packageParams.put("notify_url", Constants.pay_notify_url);//支付成功后的回调地址
            packageParams.put("spbill_create_ip", ip);//支付方式
            packageParams.put("openid", openid);
            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
            String mysign = PayUtil.sign(prestr, Constants.pay_key, "utf-8").toUpperCase();

            //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
            String xml = "<xml>" + "<mch_appid>" + Constants.pay_appid + "</mch_appid>"
                   // + "<body>" + desc +"</body>"
                    + "<mchid>" + Constants.pay_mch_id + "</mchid>"
                    + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<partner_trade_no>" + orderNo + "</partner_trade_no>"
                    + "<openid>" +openid + "</openid>"
                    + "<check_name>" +"NO_CHECK" + "</check_name>"
                    + "<amount>" + amount + "</amount>"
                    + "<desc>" + desc + "</desc>"
                    + "<spbill_create_ip>" + ip + "</spbill_create_ip>"
                    + "<sign>" + mysign + "</sign>"
                    + "</xml>";

            log.info	("调试模式_提现接口 请求XML数据：" + xml);

            //调用统一下单接口，并接受返回的结果
            String resXml = CertHttpUtil.postData("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers", xml);

            log.info("调试模式_提现接口 返回XML数据：" + resXml);
  

            // 将解析结果存储在HashMap中
            Map<String,String> map = PayUtil.doXMLParse(resXml);
            resp.setXmlString(resXml);
            String return_code =  map.get("return_code");//返回状态码
            if(isOk(return_code)){
            	String result_code = map.get("result_code");
            	if(isOk(result_code)){
            		resp.setSuccess(true);
            		String partner_trade_no = map.get("partner_trade_no");
            		String payment_no = map.get("payment_no");
            		String payment_time = map.get("payment_time");
            		resp.setPartnerTradeNo(partner_trade_no);
            		resp.setPaymentNo(payment_no);
            		resp.setPaymentTime(payment_time);
            		return resp;
            	}
            	resp.setErrCode(map.get("err_code"));
          	    resp.setErrCodeDes(map.get("err_code_des"));
            
            } 
        }catch(Exception e){
            e.printStackTrace();
        }
        return resp;
    }
    
    /**
     * 查询企业付款
     * @param partner_trade_no
     * @return
     */
    public static PayTransfersResult getTransferinfo(String partner_trade_no){
    	 PayTransfersResult result = new PayTransfersResult();
    	try{
            //生成的随机字符串
            String nonce_str = PayUtil.getRandomStringByLength(32);
            //组装参数，查询企业付款接口的签名
            Map<String, String> packageParams = new HashMap<String, String>();
            packageParams.put("appid", Constants.pay_appid);
            packageParams.put("mch_id", Constants.pay_mch_id);
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("partner_trade_no", partner_trade_no);
  
            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
            String mysign = PayUtil.sign(prestr, Constants.pay_key, "utf-8").toUpperCase();

            //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
            String xml = "<xml>" + "<appid>" + Constants.pay_appid + "</appid>"
                   // + "<body>" + desc +"</body>"
                    + "<mch_id>" + Constants.pay_mch_id + "</mch_id>"
                    + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<partner_trade_no>" + partner_trade_no + "</partner_trade_no>"
                    + "<sign>" + mysign + "</sign>"
                    + "</xml>";

            log.info("调试模式_查询企业付款请求XML数据：" + xml);

            //调用统一下单接口，并接受返回的结果
            String resXml = CertHttpUtil.postData("https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo", xml);

            log.info("调试模式_查询企业付款接口 返回XML数据：" + resXml);
  

            // 将解析结果存储在HashMap中
            Map<String,String> map = PayUtil.doXMLParse(resXml);
            result.setXmlString(resXml);
            String return_code =  map.get("return_code");//返回状态码
            if(isOk(return_code)){
            	String result_code = map.get("result_code");
            	if(isOk(result_code)){
            		result.setStatus(map.get("status"));
            		if("SUCCESS".equals(map.get("status"))){
            			result.setSuccess(true);
            		}
            		result.setPaymentNo(map.get("detail_id"));
            		result.setPartnerTradeNo(map.get("partner_trade_no"));
            		//String payment_no = map.get("payment_time");
            		//String payment_time = map.get("payment_time");
            		/*resp.setPartnerTradeNo(partner_trade_no);
            		resp.setPaymentNo(payment_no);
            		resp.setPaymentTime(payment_time);
            		return resp;*/
            		return result;
            	}
            
            } 
        }catch(Exception e){
            e.printStackTrace();
        }
        return result;
    }
    
   
    /**
     * 查询订单状态
     * @param partner_trade_no
     * @return
     */
    public static PayTransfersResult orderquery(String partner_trade_no){
    	PayTransfersResult result = new PayTransfersResult();
    	try{
           //生成的随机字符串
           String nonce_str = PayUtil.getRandomStringByLength(32);
           //组装参数，查询企业付款接口的签名
           Map<String, String> packageParams = new HashMap<String, String>();
           packageParams.put("appid", Constants.WeChatAPPID);
           packageParams.put("mch_id", Constants.pay_mch_id);
           packageParams.put("nonce_str", nonce_str);
           packageParams.put("out_trade_no", partner_trade_no);
 
           String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
           //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
           String mysign = PayUtil.sign(prestr, Constants.pay_key, "utf-8").toUpperCase();

           //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
           String xml = "<xml>" + "<appid>" +Constants.WeChatAPPID + "</appid>"
                  // + "<body>" + desc +"</body>"
                   + "<mch_id>" + Constants.pay_mch_id + "</mch_id>"
                   + "<nonce_str>" + nonce_str + "</nonce_str>"
                   + "<out_trade_no>" + partner_trade_no + "</out_trade_no>"
                   + "<sign>" + mysign + "</sign>"
                   + "</xml>";

           log.info("调试模式_查询订单付款请求XML数据：" + xml);

           //调用统一下单接口，并接受返回的结果
           String resXml = CertHttpUtil.postData("https://api.mch.weixin.qq.com/pay/orderquery", xml);

           log.info("调试模式_查询订单接口 返回XML数据：" + resXml);
 

           // 将解析结果存储在HashMap中
           Map<String,String> map = PayUtil.doXMLParse(resXml);
           result.setXmlString(resXml);
           String return_code =  map.get("return_code");//返回状态码
           if(isOk(return_code)){
        	   	String result_code = map.get("result_code");
           		if(isOk(result_code)){
           			result.setStatus(map.get("trade_state"));
           			if(isOk(map.get("trade_state"))) result.setSuccess(true);
           			result.setPaymentNo(map.get("transaction_id"));
           			result.setPartnerTradeNo(map.get("out_trade_no"));
           			return result;
           		}
           } 
       }catch(Exception e){
           e.printStackTrace();
       }
       return result;
   }
    /**
     * h5 下单
     * @param body
     * @param price
     * @param orderNo
     * @param ip
     * @param wap_url
     * @return
     */
   public static PayUnifiedorderResult  h5Unifiedorder( String body,int price,String orderNo,String ip,String wap_url){
	   PayUnifiedorderResult resp = new PayUnifiedorderResult();
	  // ip = "112.17.80.113";
   	   try{
           //生成的随机字符串
           String nonce_str = PayUtil.getRandomStringByLength(32);
           //组装参数，用户生成统一下单接口的签名  
           Map<String, String> packageParams = new HashMap<String, String>();
           packageParams.put("appid", Constants.h5_pay_appid);
           packageParams.put("mch_id", Constants.pay_mch_id);
           packageParams.put("nonce_str", nonce_str);
           packageParams.put("body", body);       
           packageParams.put("out_trade_no", orderNo);//商户订单号
           packageParams.put("total_fee", String.valueOf(price));//支付金额，这边需要转成字符串类型，否则后面的签名会失败
           packageParams.put("spbill_create_ip", ip);
           packageParams.put("notify_url", Constants.pay_notify_url);//支付成功后的回调地址
           packageParams.put("trade_type", Constants.h5_pay_TRADETYPE);//支付方式
           JSONObject h5_info = new JSONObject();
           h5_info.put("type", "Wap");
           h5_info.put("wap_url", wap_url);
           h5_info.put("wap_name", "地心引力");
           JSONObject scene_info = new JSONObject();
           scene_info.put("h5_info", h5_info);
           String scene_info_str = scene_info.toJSONString();
          
           packageParams.put("scene_info", scene_info_str);
           String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
           
           //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
           String mysign = PayUtil.sign(prestr, Constants.pay_key, "utf-8").toUpperCase();

           //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
           String xml = "<xml>" + "<appid>" +  Constants.h5_pay_appid + "</appid>"
                   + "<body><![CDATA[" + body + "]]></body>"
                   + "<mch_id>" + Constants.pay_mch_id + "</mch_id>"
                   + "<nonce_str>" + nonce_str + "</nonce_str>"
                   + "<notify_url>" + Constants.pay_notify_url + "</notify_url>"
                   + "<out_trade_no>" + orderNo + "</out_trade_no>"
                   + "<spbill_create_ip>" + ip + "</spbill_create_ip>"
                   + "<total_fee>" + price + "</total_fee>"
                   + "<trade_type>" + Constants.h5_pay_TRADETYPE + "</trade_type>"
                    +"<scene_info>" + scene_info_str + "</scene_info>"
                   + "<sign>" + mysign + "</sign>"
                   + "</xml>";

           log.info("调试模式_h5统一下单接口 请求XML数据：" + xml);

           //调用统一下单接口，并接受返回的结果
           String result = PayUtil.httpRequest(Constants.pay_url, "POST", xml);

           log.info("调试模式_h5统一下单接口 返回XML数据：" + result);
 

           // 将解析结果存储在HashMap中
           Map<String,String> map = PayUtil.doXMLParse(result);
           
           String return_code =  map.get("return_code");//返回状态码
           if(isOk(return_code)){
        	   String result_code =  map.get("result_code");//返回状态码
        	   if(isOk(result_code)){  		   
        		   resp.setSuccess(true);
        		   String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
        		   resp.setPrepayId(prepay_id);
        		   resp.setMwebUrl(map.get("mweb_url"));
        	   }
        	   resp.setNoncestr(nonce_str);
        	   resp.setErrCode(map.get("err_code"));
        	   resp.setErrCodeDes(map.get("err_code_des"));
           } 
       }catch(Exception e){
           e.printStackTrace();
       }
       return resp;
   }
   
   /**
    * 查询订单状态
    * @param partner_trade_no
    * @return
    */
   public static PayTransfersResult refundquery(String partner_trade_no){
   	PayTransfersResult result = new PayTransfersResult();
   	try{
          //生成的随机字符串
          String nonce_str = PayUtil.getRandomStringByLength(32);
          //组装参数，查询企业付款接口的签名
          Map<String, String> packageParams = new HashMap<String, String>();
          packageParams.put("appid", Constants.pay_appid);
          packageParams.put("mch_id", Constants.pay_mch_id);
          packageParams.put("nonce_str", nonce_str);
          packageParams.put("out_trade_no", partner_trade_no);

          String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
          //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
          String mysign = PayUtil.sign(prestr, Constants.pay_key, "utf-8").toUpperCase();

          //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
          String xml = "<xml>" + "<appid>" + Constants.pay_appid + "</appid>"
                 // + "<body>" + desc +"</body>"
                  + "<mch_id>" + Constants.pay_mch_id + "</mch_id>"
                  + "<nonce_str>" + nonce_str + "</nonce_str>"
                  + "<out_trade_no>" + partner_trade_no + "</out_trade_no>"
                  + "<sign>" + mysign + "</sign>"
                  + "</xml>";

          log.info("调试模式_查询订单付款请求XML数据：" + xml);

          //调用统一下单接口，并接受返回的结果
          String resXml = CertHttpUtil.postData("https://api.mch.weixin.qq.com/pay/refundquery", xml);

          log.info("调试模式_查询订单接口 返回XML数据：" + resXml);


          // 将解析结果存储在HashMap中
          Map<String,String> map = PayUtil.doXMLParse(resXml);
          result.setXmlString(resXml);
          String return_code =  map.get("return_code");//返回状态码
          if(isOk(return_code)){
       	   	String result_code = map.get("result_code");
          		if(isOk(result_code)){
          			result.setStatus(map.get("refund_status_0"));
          			if(isOk(map.get("refund_status_0"))) result.setSuccess(true);
          			result.setPaymentNo(map.get("transaction_id"));
          			result.setPartnerTradeNo(map.get("out_trade_no"));
          			return result;
          		}
          } 
      }catch(Exception e){
          e.printStackTrace();
      }
      return result;
  }
   
   private static boolean isOk(String return_code){
	   return return_code == "SUCCESS"||return_code.equals("SUCCESS");
   }
   
/*   public static void main(String[] args) {
	  PayTransfersResult re = orderquery("2018090217372577120089031");
	   //PayRefundResult re =  refund(Constants.WeChatAPPID, "2018083118083219480017056", "TK2018083118083219480017056", 10, 10, "");
	   //refundquery("2018083118083219480017056");
	  // System.out.println(re);
}*/
    
}  